package com.macro.mall.portal.config.sharding;

import cn.hutool.core.util.HashUtil;
import cn.hutool.setting.dialect.Props;
import lombok.extern.slf4j.Slf4j;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingAlgorithm;
import org.apache.shardingsphere.api.sharding.standard.PreciseShardingValue;

import java.util.Collection;

/**
 * 自定义数据库的精确分片算法，根据用户名进行分片
 * @author wwj
 */
@Slf4j
public class CustomPreciseDBShardingAlgorithm implements PreciseShardingAlgorithm<Long> {

    /**
     * 分库虚拟节点数量
     */
    private static int virtualNodeCount;
    /**
     * 分库虚拟节点范围
     */
    private static String virtualNodeCountRang;

    @Override
    public String doSharding(Collection<String> dbNames, PreciseShardingValue<Long> preciseShardingValue) {

        Props props = new Props("application-shardingJDBC.properties");
        virtualNodeCount = props.getInt(ShardingConstant.SHARDING_DATASOURCE_VIRTUAL_NODE_COUNT);
        virtualNodeCountRang = props.getStr(ShardingConstant.SHARDING_DATASOURCE_VIRTUAL_NODE_COUNT_RANG);


        int hash = HashUtil.rsHash(preciseShardingValue.getValue() + "");
        // 根据用户名的hash值对《virtualNodeCount》进行取余后，得到余数，余数一定在0，《virtualNodeCount》之间的
        Integer mod = hash % virtualNodeCount;

        // 由于获取的字符串的hash值可能存在负数，所以需要需要取其绝对值
        mod = ShardingUtils.getAbsoluteValue(mod);

        Integer physicNode = ShardingUtils.getPhysicNodeByVisualNode(mod, virtualNodeCountRang);

        for (String dbName : dbNames) {
            // todo ： 数据库节点为0-12，则physicNode ==2 ,则endsWith会匹配到2和12的情况
            if (dbName.endsWith(String.valueOf(physicNode))) {
                log.info("logic db :{}", dbName);
                return dbName;
            }
        }
        throw new UnsupportedOperationException();
    }
}
